package com.hedl.elasticsearch.service.impl;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.mapping.DateProperty;
import co.elastic.clients.elasticsearch._types.mapping.Property;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.bulk.BulkResponseItem;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.indices.*;
import co.elastic.clients.transport.endpoints.BooleanResponse;
import com.hedl.elasticsearch.po.User;
import com.hedl.elasticsearch.service.ElasticsearchService;
import lombok.extern.slf4j.Slf4j;
import org.junit.platform.commons.util.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * ProjectName: stuy-elasticsearch
 * DateTime: 2023/9/9 21:19
 * Author: Big Watermelon
 * Description:
 */
@Service
@Slf4j
public class ElasticsearchServiceImpl<T> implements ElasticsearchService<T> {

    @Resource
    private ElasticsearchClient elasticsearchClient;

    /**
     * 判断索引是否存在.
     * @param indexName index名称
     */
    @Override
    public boolean existIndex(String indexName) {
        try {
            BooleanResponse booleanResponse = elasticsearchClient.indices().exists(e -> e.index(indexName));
            return booleanResponse.value();
        } catch (IOException e) {
            log.error("向es中检测索引【{}】出错，错误信息为：{}", indexName, e.getMessage());
            throw new RuntimeException("向es中检测索引【"+indexName+"】出错");
        }
    }

    /**
     * 创建索引.
     * @param indexName index名称
     */
    @Override
    public void createIndex(String indexName) {
        try {
            Map<String, Property> documentMap = new HashMap<>();
            documentMap.put("createTime", Property.of(property ->
                            property.date(DateProperty.of(dateProperty ->
                                            dateProperty.index(true).format("epoch_millis"))
                                    //textProperty.index(true))
                            )
                    )
            );
            elasticsearchClient.indices().create(c -> c.index(indexName).mappings(mappings ->
                    mappings.properties(documentMap)));
        } catch (IOException e) {
            log.error("向es中创建索引【{}】出错，错误信息为：{}", indexName, e.getMessage());
        }
    }

    /**
     * 添加记录.
     */
    @Override
    public void addDocument(T data, String indexName) {
        try {
            if (!this.existIndex(indexName)) {
                this.createIndex(indexName);
            }
            elasticsearchClient.index(i -> i.index(indexName).id(null).document(data));
        } catch (IOException e) {
            log.error("向es中添加document出错:{}", e.getMessage());
        }
    }

    /**
     * 批量添加.
     * @param dataList 添加的数量集合
     * @param indexName indexName
     */
    @Override
    public void batchAddDocument(List<T> dataList, String indexName) {
        if (!this.existIndex(indexName)) {
            this.createIndex(indexName);
        }

        BulkRequest.Builder br = new BulkRequest.Builder();
        dataList.forEach(data -> br.operations(op -> op
                .index(idx -> idx
                        .index(indexName)
                        .id(null)
                        .document(data)
                ))
        );

        try {
            BulkResponse result = elasticsearchClient.bulk(br.build());
            if (result.errors()) {
                log.error("Bulk had errors");
                for (BulkResponseItem item : result.items()) {
                    if (item.error() != null) {
                        log.error(item.error().reason());
                    }
                }
            }
        } catch (IOException e) {
            log.error("向es中添加document出错:{}",e.getMessage());
        }
    }

    /**
     * 根据索引名称和字段查询数据.
     *
     * @param indexName 索引名称
     * @param filedValue 查询字段值
     * @param filedName 查询字段名称
     */
    @Override
    public List<T> findDataList(String indexName, String filedName, String filedValue,Class<T> className) {
        try {
            SearchResponse<T> searchResponse = elasticsearchClient.search(s -> s.index(indexName)
                            .query(q -> q
                                    .match(t -> t
                                            .field(filedName)
                                            .query(filedValue)
                                    )),
                    className);
            List<Hit<T>> hitList = searchResponse.hits().hits();
            List<T> dataList = new ArrayList<>();
            for (Hit<T> mapHit : hitList) {
                dataList.add(mapHit.source());
            }
            return dataList;
        } catch (IOException e) {
            log.error("【查询 -> 失败】从es中查询分析后的日志出错，错误信息为：{}", e.getMessage());
        }
        return null;
    }

    /**
     * 使用索引名查询_search
     * @param indexName 索引名称
     * @return
     */
    @Override
    public SearchResponse<User> getIndexSearch(String indexName){
        if(!StringUtils.isNotBlank(indexName)){
            throw new RuntimeException("index is null!");
        }
        try{
            if (this.existIndex(indexName)){
                return elasticsearchClient.search(s -> s.index(indexName), User.class);
            }
            throw new RuntimeException("index is error!");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 普通索引查询
     * @param indexName
     * @return
     */
    @Override
    public GetIndexResponse getIndex(String indexName){
        GetIndexRequest request;
        if(!StringUtils.isNotBlank(indexName)){
            throw new RuntimeException("index is null!");
        }
        try {
            if (this.existIndex(indexName)){
                 request = new GetIndexRequest
                         .Builder()
                         .index(indexName).build();
                return elasticsearchClient.indices().get(request);
            }
            throw new RuntimeException("index is error!");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 指定删除索引
     * @param indexName 索引名称
     * @return
     */
    @Override
    public DeleteIndexResponse deleteIndex(String indexName){
        DeleteIndexRequest request;
        if(!StringUtils.isNotBlank(indexName)){
            throw new RuntimeException("index is null!");
        }
        try {
            if (this.existIndex(indexName)){
                request = new DeleteIndexRequest
                        .Builder()
                        .index(indexName).build();
                return elasticsearchClient.indices().delete(request);
            }
            throw new RuntimeException("index is error!");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 添加文档数据
     * @param indexName 索引名称
     * @param id ID
     * @param source 数据
     * @return
     */
    @Override
    public IndexResponse insertDocsData(String indexName,String id,T source){
        try{
            if (!this.existIndex(indexName)) {
                this.createIndex(indexName);
            }
            return elasticsearchClient.index(
                    i -> i.index(indexName).id(id).document(source));
        }catch (IOException e){
            throw new RuntimeException(e);
        }
    }




}


